# -*- coding: UTF-8 -*-
'''
@Project ：push_rk
@File ：app.py
@IDE ：PyCharm
@Author ：苦瓜
@Date ：2025/10/11 10:24
@Note: Something beautiful is about to happen !
'''
import os.path

from flask import Flask, render_template, request
from keras.src.utils import load_img, img_to_array
from model import MyLeNet5, TrainerConfig

app = Flask(__name__)

model = MyLeNet5(4)
model.build((None, 28, 28, 1))
model.load_weights("model.weights.h5")


# 2.	Web应用的搭建功能性约束
# 1)	Web应用设置：
# 使用Flask框架创建一个Web应用。
# 设置应用以调试模式运行，并监听所有IP地址的6008端口。
# 2)	图像读取与处理：
# 定义一个read_image函数，用于读取用户上传的图像文件，并将其处理成模型所需的输入格式（28x28像素的灰度图，像素值归一化到0-1之间）。
def read_image(path_):
    img = load_img(path_, color_mode='grayscale', target_size=(-1, 28, 28, 1))
    img = img_to_array(img).astype("float32") / 255.
    return img


# 3)	模型加载与预测：
# 导入mnist_lenet5模块，并创建一个LeNet-5模型实例。
# 加载预先训练好的模型权重。
# 定义一个predict路由，处理用户上传的图像文件，并使用模型进行预测。
@app.route("/")
def home():
    return render_template("home.html")


@app.route("/predict", methods=["POST"])
def predict():
    try:
        if request.method == "POST":
            file_in = request.files['file']
            if not file_in:
                return render_template("error.html", msg="文件不存在!")
            img_list = ["jpg", 'png']
            if file_in.filename.split(".")[-1] not in img_list:
                return render_template("error.html", msg="图片格式不对，请重新上传!")
            # 保存图片
            path_ = os.path.join('static/images', file_in.filename)
            file_in.save(path_)
            # 判断图片的大小
            if os.path.getsize(path_) > 1024 * 1024 * 5:
                os.remove(path_)
                return render_template("error.html", msg="图片过大，请修正上传！!")
            # 处理图片
            img = read_image(path_)
            # 预测图片
            y_pred_index = model.predict(img).argmax()
            return render_template('predict.html', product=TrainerConfig.product_dict[y_pred_index], user_image=path_)
        else:
            return render_template("predict.html")
    except Exception as e:
        return render_template("error.html", msg=f"{e}")


# 预测结果为用户上传图像中的手写数字。
# 4)	用户交互：
# 提供一个HTML页面（home.html），允许用户上传图像文件。
# 当用户提交图像文件时，将其保存到服务器上的static/images目录。
# 使用模型对保存的图像进行预测，并将预测结果以及用户上传的图像显示在另一个HTML页面（predict.html）上。
# 5)	错误处理：
# 在预测路由中捕获并处理可能发生的异常，将异常信息返回给用户。
if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0", port=6008)
